"#include \"AtmosphereShadersCommon.fxh\"\n"
"\n"
"\n"
"cbuffer cbParticipatingMediaScatteringParams\n"
"{\n"
"    AirScatteringAttribs g_MediaParams;\n"
"}\n"
"\n"
"float2 IntegrateParticleDensity(float3 f3Start, \n"
"                                float3 f3End,\n"
"                                float3 f3EarthCentre,\n"
"                                int    iNumSteps )\n"
"{\n"
"    float3 f3Step = (f3End - f3Start) / float(iNumSteps);\n"
"    float fStepLen = length(f3Step);\n"
"        \n"
"    float fStartHeightAboveSurface = abs( length(f3Start - f3EarthCentre) - g_MediaParams.fEarthRadius );\n"
"    float2 f2PrevParticleDensity = exp( -fStartHeightAboveSurface * g_MediaParams.f4ParticleScaleHeight.zw );\n"
"\n"
"    float2 f2ParticleNetDensity = float2(0.0, 0.0);\n"
"    for (int iStepNum = 1; iStepNum <= iNumSteps; ++iStepNum)\n"
"    {\n"
"        float3 f3CurrPos = f3Start + f3Step * float(iStepNum);\n"
"        float fHeightAboveSurface = abs( length(f3CurrPos - f3EarthCentre) - g_MediaParams.fEarthRadius );\n"
"        float2 f2ParticleDensity = exp( -fHeightAboveSurface * g_MediaParams.f4ParticleScaleHeight.zw );\n"
"        f2ParticleNetDensity += (f2ParticleDensity + f2PrevParticleDensity) * fStepLen / 2.0;\n"
"        f2PrevParticleDensity = f2ParticleDensity;\n"
"    }\n"
"    return f2ParticleNetDensity;\n"
"}\n"
"\n"
"float2 IntegrateParticleDensityAlongRay(float3     f3Pos, \n"
"                                        float3     f3RayDir,\n"
"                                        float3     f3EarthCentre, \n"
"                                        const int  iNumSteps,\n"
"                                        const bool bOccludeByEarth)\n"
"{\n"
"    if( bOccludeByEarth )\n"
"    {\n"
"        // If the ray hits the bottom atmosphere boundary, return huge optical depth\n"
"        float2 f2RayEarthIsecs; \n"
"        GetRaySphereIntersection(f3Pos, f3RayDir, f3EarthCentre, g_MediaParams.fAtmBottomRadius, f2RayEarthIsecs);\n"
"        if( f2RayEarthIsecs.x > 0.0 )\n"
"            return float2(1e+20, 1e+20);\n"
"    }\n"
"\n"
"    // Get intersection with the top of the atmosphere (the start point must always be under the top of it)\n"
"    //      \n"
"    //                     /\n"
"    //                .   /  . \n"
"    //      .  \'         /\\         \'  .\n"
"    //                  /  f2RayAtmTopIsecs.y > 0\n"
"    //                 *\n"
"    //                   f2RayAtmTopIsecs.x < 0\n"
"    //                  /\n"
"    //      \n"
"    float2 f2RayAtmTopIsecs;\n"
"    GetRaySphereIntersection(f3Pos, f3RayDir, f3EarthCentre, g_MediaParams.fAtmTopRadius, f2RayAtmTopIsecs);\n"
"    float fIntegrationDist = f2RayAtmTopIsecs.y;\n"
"\n"
"    float3 f3RayEnd = f3Pos + f3RayDir * fIntegrationDist;\n"
"\n"
"    return IntegrateParticleDensity(f3Pos, f3RayEnd, f3EarthCentre, iNumSteps);\n"
"}\n"
"\n"
"void PrecomputeNetDensityToAtmTopPS( FullScreenTriangleVSOutput VSOut,\n"
"                                     out float2 f2Density : SV_Target0 )\n"
"{\n"
"    float2 f2UV = NormalizedDeviceXYToTexUV(VSOut.f2NormalizedXY);\n"
"    // Do not allow start point be at the Earth surface and on the top of the atmosphere\n"
"    float fStartHeight = clamp( lerp(g_MediaParams.fAtmBottomAltitude, g_MediaParams.fAtmTopAltitude, f2UV.x), 10.0, g_MediaParams.fAtmTopAltitude-10.0 );\n"
"\n"
"    float fCosTheta = f2UV.y * 2.0 - 1.0;\n"
"    float fSinTheta = sqrt( saturate(1.0 - fCosTheta*fCosTheta) );\n"
"    float3 f3RayStart = float3(0.0, 0.0, fStartHeight);\n"
"    float3 f3RayDir = float3(fSinTheta, 0.0, fCosTheta);\n"
"    \n"
"    float3 f3EarthCentre = float3(0.0, 0.0, -g_MediaParams.fEarthRadius);\n"
"\n"
"    const int iNumSteps = 200;\n"
"    f2Density = IntegrateParticleDensityAlongRay(f3RayStart, f3RayDir, f3EarthCentre, iNumSteps, true);\n"
"}\n"
